/* 
 * date:    2024-07-19
 * version: v1.3.0.0
 * author:  zijian666
 */
// 扩展 Date
(() => {
    function not(property) {
        return !Date.prototype.hasOwnProperty(property);
    }

    if (not("__toString__")) {
        Date.prototype.__toString__ = Date.prototype.toString;

        function frontadd(num, decimal) {
            let i = parseInt(num);
            if (i < 0) {
                i *= -1;
                return "-" + ("0000" + i).slice(-(decimal || 2))
            }
            return ("0000" + i).slice(-(decimal || 2))
        };

        const weekNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
        const cnWeekNames = ["一", "二", "三", "四", "五", "六", "日"];
        const monthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
        const cnMonthNames = ["一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二"];

        const formatters = {
            "yyyy": function (date) { return date.getFullYear() },
            "yyy": function (date) { return date.getYear() },
            "yy": function (date) { return date.getFullYear() % 100 },
            "MMMMM": function (date) { return cnMonthNames[date.getMonth()] },
            "MMMM": function (date) { return monthNames[date.getMonth()] },
            "MMM": function (date) { return monthNames[date.getMonth()].substr(0, 3) },
            "MM": function (date) { return frontadd(date.getMonth() + 1) },
            "M": function (date) { return date.getMonth() + 1 },
            "dddd": function (date) { return weekNames[date.getDay()] },
            "ddd": function (date) { return weekNames[date.getDay()].substr(0, 3) },
            "E": function (date) { return weekNames[date.getDay()] },
            "DDDD": function (date) { return "星期" + cnWeekNames[date.getDay()] },
            "DDD": function (date) { return "周" + cnWeekNames[date.getDay()] },
            "u": function (date) { return date.getDay() + 1 },
            "dd": function (date) { return frontadd(date.getDate()) },
            "d": function (date) { return date.getDate() },
            "HH": function (date) { return frontadd(date.getHours()) },
            "H": function (date) { return date.getHours() },
            "hh": function (date) { return frontadd(date.getHours() % 12) },
            "h": function (date) { return date.getHours() % 12 },
            "mm": function (date) { return frontadd(date.getMinutes()) },
            "mi": function (date) { return date.getMilliseconds() },
            "m": function (date) { return date.getMinutes() },
            "ss": function (date) { return frontadd(date.getSeconds()) },
            "s": function (date) { return date.getSeconds() },
            "SSS": function (date) { return frontadd(date.getMilliseconds(), 3) },
            "SS": function (date) { return frontadd(date.getMilliseconds(), 3).substr(0, 2) },
            "S": function (date) { return frontadd(date.getMilliseconds(), 3).substr(0, 1) },
            "fff": function (date) { return frontadd(date.getMilliseconds(), 3) },
            "ff": function (date) { return frontadd(date.getMilliseconds(), 3).substr(0, 2) },
            "f": function (date) { return frontadd(date.getMilliseconds(), 3).substr(0, 1) },
            "tt": function (date) { return date.getHours() > 12 ? "PM" : "AM" },
            "a": function (date) { return date.getHours() > 12 ? "PM" : "AM" },
            "t": function (date) { return date.getHours() > 12 ? "P" : "A" },
            "TT": function (date) { return date.getHours() > 12 ? "下午" : "上午" },
            "T": function (date) { return date.getHours() > 12 ? "下" : "上" },
            "zzz": function (date) { return frontadd(date.getTimezoneOffset() / 60) + ":" + frontadd(date.getTimezoneOffset() % 60) },
            "zz": function (date) { return frontadd(date.getTimezoneOffset() / 60) },
            "z": function (date) { return date.getTimezoneOffset() / 60 },
        };

        const regex = new RegExp("'[^']+'|" + Object.keys(formatters).sort((x, y) => y.length - x.length).map(x => "(" + x + ")").join("|"), "g")

        Date.prototype.isInvalid = function () {
            return isNaN(this.getTime());
        }

        Date.prototype.toString = function (format) {
            if (this.isInvalid()) {
                return "";
            }
            if (format === undefined) {
                return Date.prototype.__toString__.apply(this);
            }

            const preset = {
                [null]: "yyyy-MM-dd HH:mm:ss",
                [""]: "yyyy-MM-dd HH:mm:ss",
                "date": "yyyy-MM-dd",
                "time": "HH:mm:ss",
                "datetime": "yyyy-MM-dd HH:mm:ss",
            };

            format = preset[format] || format;

            const date = this;
            return format.replace(regex, x => {
                if (x[0] === "'") {
                    return x.slice(1, -1);
                }
                return formatters[x](date);
            });
        };
    }

    if (not("add")) {
        //时间加减
        Date.prototype.add = function (type, value) {
            if (+value !== value) {
                throw new Error("必须是数字");
            }
            var date = new Date(this);
            switch (type) {
                case 'y':
                case 'Y':
                    date.setYear(this.getFullYear() + value);
                    break;
                case 'M':
                    date.setMonths(this.getMonths() + value);
                    break;
                case 'd':
                case 'D':
                    date.setDate(this.getDate() + value);
                    break;
                case 'h':
                case 'H':
                    date.setHours(this.getHours() + value);
                    break;
                case 'm':
                    date.setMinutes(this.getMinutes() + value);
                    break;
                case 'S':
                case 's':
                    date.setSeconds(this.getSeconds() + value);
                    break;
                case 'f':
                    date.setMilliseconds(this.getMilliseconds() + value);
                    break;
                default:
                    throw Error("type只能是:y,Y,M,d,D,h,H,m,s,S,f");
            }
            return date;
        };
    }
    not("addDays") && (Date.prototype.addDays = function (value) { return this.add("d", value); });
    not("addHours") && (Date.prototype.addHours = function (value) { return this.add("h", value); });
    not("addMilliseconds") && (Date.prototype.addMilliseconds = function (value) { return this.add("f", value); });
    not("addMinutes") && (Date.prototype.addMinutes = function (value) { return this.add("m", value); });
    not("addMonths") && (Date.prototype.addMonths = function (value) { return this.add("M", value); });
    not("addSeconds") && (Date.prototype.addSeconds = function (value) { return this.add("s", value); });
    not("addYears") && (Date.prototype.addYears = function (value) { return this.add("y", value); });
    not("removeTime") && (Date.prototype.removeTime = function () { return new Date(this.getFullYear(), this.getMonth(), this.getDate()) });

    if (!Date.hasOwnProperty("__parse__")) {
        // 处理  /Date(1673575237000)/
        Date.__parse__ = Date.parse;
        Date.parse = function (dateString, strict) {
            if (typeof dateString === "string") {
                dateString = dateString.trim();
                if (/^\/Date\([1-3]?\d{10,13}\)\/$/.test(dateString)) {
                    return parseInt(dateString.slice(6, -1));
                }
                if (/^\d{4}-W\d{1,2}$/.test(dateString)) {
                    var arr = dateString.split("-W");
                    var year = parseInt(arr[0]);
                    var week = parseInt(arr[1]);
                    if (week <= 54 && week >= 0) {
                        var day = (week - 1) * 7 + 2; // 默认从周日开始,中国从周一开始 所以+2 
                        return new Date(year, 0, day);
                    }
                }
                // 严格模式必须4位数字开头
                if (strict === true && !/^\d{4}/.test(dateString)) {
                    return Number.NaN;
                }
            }
            return Date.__parse__(dateString);
        }
    }

})();